﻿using System;
using System.Net;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.ServiceModel;

namespace MrCRM.Silverlight.SynchronousWCF
{
	public static class ICommunicationObjectExtensions
	{
		public static TEventArgs SynchronousCall<TEventArgs>(this ICommunicationObject Client, string Method, params object[] Parameters) where TEventArgs : EventArgs
		{
			Type clientType = Client.GetType();

			string methodName = Method + "Async";
			string completedName = Method + "Completed";

			MethodInfo[] methods = null;

			try
			{
				methods = clientType.GetMethods().Where(x => x.Name == methodName).ToArray();
			}
			catch { }

			if (methods == null || methods.Length == 0)
			{
				throw new MissingMethodException(methodName + " not found");
			}

			MethodInfo method = null;

			try
			{
				method = methods.Single(x => x.GetParameters().Length == Parameters.Length);
			}
			catch { }

			if (method == null)
			{
				throw new MissingMethodException(methodName + " parameter count mismatch");
			}

			EventInfo completedEvent = null;

			try
			{
				completedEvent = clientType.GetEvent(completedName);
			}
			catch { }

			if (completedEvent == null)
			{
				throw new MissingMemberException(completedName + " not found");
			}

			ManualResetEvent reset = new ManualResetEvent(false);

			EventHandler<TEventArgs> completedHandler = null;

			TEventArgs args = null;

			completedHandler = (s, e) =>
			{
				completedEvent.RemoveEventHandler(Client, completedHandler);

				args = e;

				reset.Set();
			};

			completedEvent.AddEventHandler(Client, completedHandler);

			method.Invoke(Client, Parameters);

			reset.WaitOne();

			return args;
		}
	}
}
